package system

import (
	"context"
	"errors"
	"fmt"
	"time"

	"admin_template/bff/admin/hertz_gen/base"
	genSysApi "admin_template/bff/admin/hertz_gen/system/sys_api"
	"admin_template/bff/admin/internal/base/data"
	"admin_template/bff/admin/internal/entity/ent"
	"admin_template/bff/admin/internal/entity/ent/predicate"
	"admin_template/bff/admin/internal/entity/ent/sysapi"
	"admin_template/bff/admin/internal/entity/ent/sysrole"
	"admin_template/bff/admin/internal/service/system"

	"gitee.com/byx_darwin/go-tools/kitex/rpc_error"
	"gitee.com/byx_darwin/go-tools/tools/cache"
	cacheCore "gitee.com/byx_darwin/go-tools/tools/cache/core"
	toolsTime "gitee.com/byx_darwin/go-tools/tools/time"
	pkgErrors "github.com/pkg/errors"
)

type apiRepo struct {
	*data.Data
	db           *ent.SysApiClient
	defaultCache cache.Cache[string, struct{}]
}

func NewApiRepo(d *data.Data) system.ApiRepo {
	return &apiRepo{
		Data:         d,
		db:           d.DB.SysApi,
		defaultCache: cacheCore.NewLruCache[string, struct{}](100),
	}
}

func (repo *apiRepo) Add(ctx context.Context,
	req any) error {
	info, ok := req.(*genSysApi.AddRequest)
	if !ok {
		return rpc_error.NewBizStatusError(rpc_error.ErrorTypeInvalid,
			errors.New(" *genSysApi.AddRequest"))
	}
	err := repo.db.Create().
		SetPath(info.Path).
		SetDescription(info.Desc).
		SetMethod(info.Method).
		SetAPIGroup(info.ApiGroup).
		SetDefault(info.Default).
		Exec(ctx)
	if err != nil {
		msg := fmt.Sprintf("sys api create(path:%s method:%s)",
			info.Path, info.Method)
		if ent.IsConstraintError(err) {
			err = pkgErrors.Wrap(err, msg)
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeDataRepeat, err)
		} else {
			err = pkgErrors.Wrap(err, msg)
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlInsertFailure, err)
		}
	}
	return nil

}

func (repo *apiRepo) UpdateInfo(ctx context.Context,
	req any) error {
	info, ok := req.(*genSysApi.UpdateRequest)
	if !ok {
		return rpc_error.NewBizStatusError(rpc_error.ErrorTypeInvalid,
			errors.New(" *genSysApi.UpdateRequest"))
	}
	err := repo.db.UpdateOneID(int(info.Id)).
		SetPath(info.Path).
		SetDescription(info.Desc).
		SetMethod(info.Method).
		SetAPIGroup(info.ApiGroup).
		SetDefault(info.Default).
		Exec(ctx)
	if err != nil {
		msg := fmt.Sprintf("sys api create(ID:%d,path:%s method:%s)",
			info.Id, info.Path, info.Method)
		if ent.IsConstraintError(err) {
			err = pkgErrors.Wrap(err, msg)
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeDataRepeat, err)
		} else {
			err = pkgErrors.Wrap(err, msg)
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlUpdateFailure, err)
		}
	}
	repo.defaultCache.Empty()
	return nil
}
func (repo *apiRepo) StateUpdate(ctx context.Context, info *base.StateUpdateRequest) error {
	switch info.State {
	case 0:
		err := repo.db.UpdateOneID(int(info.ID)).SetDeleteTime(time.Now()).Exec(ctx)
		if err != nil {
			err = pkgErrors.Wrap(err,
				fmt.Sprintf("更新API状态失败(ID:%d): ", info.ID))
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlUpdateFailure, err)
		}
	case 1:
		err := repo.db.UpdateOneID(int(info.ID)).ClearDeleteTime().Exec(ctx)
		if err != nil {
			err = pkgErrors.Wrap(err,
				fmt.Sprintf("更新API状态失败(ID:%d): ", info.ID))
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlUpdateFailure, err)
		}
	case 2:
		err := repo.db.DeleteOneID(int(info.ID)).Exec(ctx)
		if err != nil {
			err = pkgErrors.Wrap(err,
				fmt.Sprintf("删除API失败(ID:%d): ", info.ID))
			return rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlDeleteFailure, err)
		}
	}
	return nil
}

func (repo *apiRepo) List(ctx context.Context,
	req any) (int64, int64, int64, []any, error) {
	info, ok := req.(*genSysApi.ListRequest)
	if !ok {
		return 0, 0, 0, nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeInvalid,
			errors.New("req not *genSysApi.ListRequest"))
	}

	predicates := make([]predicate.SysApi, 0)
	switch info.DefaultType {
	case 1:
		predicates = append(predicates, sysapi.Default(true))
	case 2:
		predicates = append(predicates, sysapi.Default(false))
	}
	switch info.State {
	case 1:
		predicates = append(predicates, sysapi.DeleteTimeIsNil())
	case 2:
		predicates = append(predicates, sysapi.DeleteTimeNotNil())
	}
	sql := repo.db.Query()
	if len(predicates) > 0 {
		sql = sql.Where(predicates...)
	}
	total, err := sql.Count(ctx)
	if err != nil {
		err = pkgErrors.Wrap(err,
			fmt.Sprintf("分页查询API总数失败: "))
		return 0, 0, 0, nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlQueryFailure, err)
	}
	if total == 0 {
		return 0, 0, 0, nil, nil
	}
	offset := (info.Page - 1) * info.Size
	list, err := sql.Select(repo.sqlSelect()...).
		Offset(int(offset)).
		Limit(int(info.Size)).Order(ent.Asc(sysapi.FieldID)).All(ctx)
	if err != nil {
		err = pkgErrors.Wrap(err,
			fmt.Sprintf("分页查询API列表失败: "))
		return 0, 0, 0, nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlQueryFailure, err)
	}
	apiList := make([]any, 0, len(list))
	for _, value := range list {
		apiList = append(apiList, repo.genInfo(value))
	}
	return int64(total), info.Page, info.Size, apiList, nil
}

func (repo *apiRepo) All(ctx context.Context,
	req any) ([]any, error) {
	info, ok := req.(*genSysApi.AllRequest)
	if !ok {
		return nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeInvalid,
			errors.New("req not *genSysApi.AllRequest"))
	}
	predicates := make([]predicate.SysApi, 0)
	switch info.DefaultType {
	case 1:
		predicates = append(predicates, sysapi.Default(true))
	case 2:
		predicates = append(predicates, sysapi.Default(false))
	}
	switch info.State {
	case 1:
		predicates = append(predicates, sysapi.DeleteTimeNotNil())
	case 2:
		predicates = append(predicates, sysapi.DeleteTimeIsNil())
	}
	sql := repo.db.Query()
	if len(predicates) > 0 {
		sql = sql.Where(predicates...)
	}
	list, err := sql.Select(repo.sqlSelect()...).
		Order(ent.Asc(sysapi.FieldID)).All(ctx)
	if err != nil {
		err = pkgErrors.Wrap(err,
			fmt.Sprintf("查询全部API列表失败: "))
		return nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlQueryFailure, err)
	}
	apiList := make([]any, 0, len(list))
	for _, value := range list {
		apiList = append(apiList, repo.genInfo(value))
	}
	return apiList, nil
}

func (repo *apiRepo) Default(ctx context.Context, path, method string) bool {
	key := path + "-" + method
	if repo.defaultCache.Len() == 0 {
		list, _ := repo.selectDefault(ctx)
		for _, v := range list {
			key := v.Path + "-" + v.Method
			repo.defaultCache.Set(key, struct{}{})
		}
	}
	return repo.defaultCache.Contains(key)
}

func (repo *apiRepo) ListByRoleID(ctx context.Context,
	roleID int64) ([]*genSysApi.Info, error) {
	list, err := repo.db.Query().
		Select(repo.sqlSelect()...).
		Where(sysapi.Or(sysapi.HasRolesWith(sysrole.ID(int(roleID))), sysapi.Default(true))).
		All(ctx)
	if err != nil {
		err = pkgErrors.Wrap(err,
			fmt.Sprintf("查询角色API列表失败: "))
		return nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlQueryFailure, err)
	}
	apiList := make([]*genSysApi.Info, 0, len(list))
	for _, v := range list {
		apiList = append(apiList, repo.genInfo(v))
	}
	return apiList, nil
}

func (repo *apiRepo) selectDefault(ctx context.Context) ([]*ent.SysApi, error) {
	return repo.db.Query().Select(repo.sqlSelect()...).Where(
		sysapi.And(sysapi.Default(true), sysapi.DeleteTimeIsNil())).All(ctx)

}

func (repo *apiRepo) One(ctx context.Context, id int) (any, error) {
	info, err := repo.db.Query().Where(sysapi.ID(id)).
		Select(repo.sqlSelect()...).First(ctx)
	if err != nil {
		if ent.IsNotFound(err) {
			return nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeDataInvalid, err)
		}
		return nil, rpc_error.NewBizStatusError(rpc_error.ErrorTypeSqlQueryFailure, err)
	}
	return repo.genInfo(info), nil
}

func (repo *apiRepo) genInfo(info *ent.SysApi) *genSysApi.Info {
	state := int32(1)
	if info.DeleteTime.Unix() > 0 {
		state = 0
	}
	return &genSysApi.Info{
		Id:         int64(info.ID),
		Path:       info.Path,
		Desc:       info.Description,
		ApiGroup:   info.APIGroup,
		Method:     info.Method,
		Default:    info.Default,
		State:      state,
		CreateTime: toolsTime.Format(info.CreateTime.Unix(), "YYYY-MM-DD HH:mm:ss", ""),
		UpdateTime: toolsTime.Format(info.UpdateTime.Unix(), "YYYY-MM-DD HH:mm:ss", ""),
	}
}

func (repo *apiRepo) sqlSelect() []string {
	return []string{
		sysapi.FieldID,
		sysapi.FieldPath,
		sysapi.FieldMethod,
		sysapi.FieldDescription,
		sysapi.FieldAPIGroup,
		sysapi.FieldDefault,
		sysapi.FieldDeleteTime,
		sysapi.FieldCreateTime,
		sysapi.FieldUpdateTime,
	}
}

func (repo *apiRepo) Init(ctx context.Context) error {
	list := make([]*genSysApi.AddRequest, 0, 37)
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/sso",
		Method:   "GET",
		Desc:     "登录",
		ApiGroup: "sso",
		Default:  true,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/captcha",
		Method:   "GET",
		Desc:     "验证码",
		ApiGroup: "captcha",
		Default:  true,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/sso",
		Method:   "DELETE",
		Desc:     "登录",
		ApiGroup: "sso",
		Default:  true,
	})
	//API组
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/api",
		Method:   "POST",
		Desc:     "新增API",
		ApiGroup: "API",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/api",
		Method:   "PUT",
		Desc:     "更新API信息",
		ApiGroup: "API",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/api",
		Method:   "DELETE",
		Desc:     "删除API",
		ApiGroup: "API",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/api/state",
		Method:   "PUT",
		Desc:     "更新API状态",
		ApiGroup: "API",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/api",
		Method:   "GET",
		Desc:     "获取API分页列表",
		ApiGroup: "API",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/api/all",
		Method:   "PUT",
		Desc:     "获取全部API信息",
		ApiGroup: "API",
		Default:  false,
	})

	//Rule组
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/rule",
		Method:   "POST",
		Desc:     "新增Rule",
		ApiGroup: "rule",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/rule",
		Method:   "PUT",
		Desc:     "更新Rule信息",
		ApiGroup: "rule",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/rule",
		Method:   "DELETE",
		Desc:     "删除Rule",
		ApiGroup: "rule",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/rule/state",
		Method:   "PUT",
		Desc:     "更新Rule状态",
		ApiGroup: "rule",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/rule",
		Method:   "GET",
		Desc:     "获取Rule分页列表",
		ApiGroup: "rule",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/rule/all",
		Method:   "GET",
		Desc:     "获取全部Rule信息",
		ApiGroup: "rule",
		Default:  false,
	})

	//角色组
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role",
		Method:   "POST",
		Desc:     "新增角色",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role",
		Method:   "PUT",
		Desc:     "更新角色信息",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role",
		Method:   "DELETE",
		Desc:     "删除角色",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role/state",
		Method:   "PUT",
		Desc:     "更新角色状态",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role/rule",
		Method:   "PUT",
		Desc:     "更新角色rule",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role/api",
		Method:   "PUT",
		Desc:     "更新角色Api",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role/rule",
		Method:   "GET",
		Desc:     "获取角色菜单权限",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role/api",
		Method:   "GET",
		Desc:     "获取角色api权限",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role",
		Method:   "GET",
		Desc:     "获取Role分页列表",
		ApiGroup: "role",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/role/all",
		Method:   "GET",
		Desc:     "获取全部Role信息",
		ApiGroup: "role",
		Default:  false,
	})

	//公司组
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/company",
		Method:   "POST",
		Desc:     "新增公司",
		ApiGroup: "公司",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/company",
		Method:   "PUT",
		Desc:     "更新公司信息",
		ApiGroup: "公司",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/company",
		Method:   "DELETE",
		Desc:     "删除公司",
		ApiGroup: "公司",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/company/state",
		Method:   "PUT",
		Desc:     "更新公司状态",
		ApiGroup: "公司",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/company",
		Method:   "GET",
		Desc:     "获取公司分页列表",
		ApiGroup: "公司",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/company/all",
		Method:   "GET",
		Desc:     "获取全部公司信息",
		ApiGroup: "公司",
		Default:  false,
	})

	//用户组
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user",
		Method:   "POST",
		Desc:     "新增用户",
		ApiGroup: "用户",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user",
		Method:   "PUT",
		Desc:     "更新用户信息",
		ApiGroup: "用户",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user/userinfo",
		Method:   "GET",
		Desc:     "获取用户信息",
		ApiGroup: "用户",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user",
		Method:   "DELETE",
		Desc:     "删除用户",
		ApiGroup: "用户",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user/state",
		Method:   "PUT",
		Desc:     "更新用户状态",
		ApiGroup: "用户",
		Default:  false,
	})

	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user/password",
		Method:   "PUT",
		Desc:     "更新用户密码",
		ApiGroup: "用户",
		Default:  false,
	})

	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user/reset_password",
		Method:   "PUT",
		Desc:     "重置密码",
		ApiGroup: "用户",
		Default:  false,
	})

	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user/rule",
		Method:   "GET",
		Desc:     "获取用户Rule",
		ApiGroup: "用户",
		Default:  false,
	})

	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user",
		Method:   "GET",
		Desc:     "获取用户分页列表",
		ApiGroup: "用户",
		Default:  false,
	})
	list = append(list, &genSysApi.AddRequest{
		Path:     "/v1/system/user/all",
		Method:   "PUT",
		Desc:     "获取全部用户信息",
		ApiGroup: "用户",
		Default:  false,
	})

	var err error
	tx, err := repo.DB.Tx(ctx)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		}
	}()
	for _, info := range list {
		err = tx.SysApi.Create().SetPath(info.Path).
			SetDescription(info.Desc).
			SetMethod(info.Method).
			SetAPIGroup(info.ApiGroup).
			SetDefault(info.Default).
			Exec(ctx)
		if err != nil {
			return err
		}
	}
	err = tx.Commit()
	if err != nil {
		return err
	}
	return nil
}
